#pragma once
//守护进程
//1.setsid();调用setsid是让当前进程自成会话，与当前的bash会话脱离关系
//这样在用户注销时，系统服务不受用户影响，一直在后台运行。
//2.调用setsid创建新会话，要求调用进程不能是进程组组长，因此我们需要fork子进程，让
//子进程创建新会话并执行后序代码。父进程直接退出即可。
//3.守护进程：a.忽略异常信号 
//b.守护进程不能直接和用户交互，也就是说守护进程已经与终端去关联了，
//所以fd,0,1,2要特殊处理，重定向到/dev/null字符文件，通常用于屏蔽/丢弃输入输出信息
//c.进程的工作路径可能要更改
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "log.hpp"
#include "err.hpp"

void Daemon()
{
    //1.忽略信号
    signal(SIGPIPE,SIG_IGN);
    signal(SIGCHLD,SIG_IGN);

    //2.不要让自己成为进程组组长
    if(fork()>0) exit(0);//父进程直接退出，子进程执行后序代码

    //子进程新建会话，自己成为会话首进程
    pid_t ret = setsid();
    if((int)ret == -1)
    {
        logMessage(Fatal,"deamon error, code: %d, string: %s",errno,strerror(errno));
        exit(SETSID_ERR);
    }
    //4.可选：更改守护进程的工作路径
    //chdir("/");
    //5.处理文件描述符0,1,2问题
    int fd = open("/dev/null",O_RDWR);
    if(fd<0)
    {
        logMessage(Fatal,"open error, code: %d, string: %s",errno,strerror(errno));
        exit(OPEN_ERR);
    }
    dup2(fd,0);
    dup2(fd,1);
    dup2(fd,2);
    close(fd);
}